1 /*
2 Copyright: Marcelo S. N. Mancini (Hipreme|MrcSnm), 2018 - 2021
3 License:   [https://creativecommons.org/licenses/by/4.0/|CC BY-4.0 License].
4 Authors: Marcelo S. N. Mancini
5 
6 	Copyright Marcelo S. N. Mancini 2018 - 2021.
7 Distributed under the CC BY-4.0 License.
8    (See accompanying file LICENSE.txt or copy at
9 	https://creativecommons.org/licenses/by/4.0/
10 */
11 module hip.hiprenderer.backend.d3d.d3dvertex;
12 
13 version(Windows):
14 version(DirectX):
15 import hip.util.string:toStringz;
16 import core.stdc.string;
17 import hip.util.conv:to;
18 import hip.error.handler;
19 import directx.d3d11;
20 import hip.util.system;
21 import hip.hiprenderer;
22 import hip.hiprenderer.backend.d3d.d3drenderer;
23 import hip.hiprenderer.shader;
24 import hip.hiprenderer.backend.d3d.d3dshader;
25 import hip.hiprenderer.vertex;
26 import hip.config.opts;
27 
28 
29 
30 /**
31 * For reflecting OpenGL API, we create an accessor with the create functions, this is a locally
32 * managed array, but you're able to get it by using the private name, for flexibility.
33 */
34 
35 class Hip_D3D11_VertexBufferObject : IHipVertexBufferImpl
36 {
37     immutable D3D11_USAGE usage;
38     ID3D11Buffer buffer;
39     ulong size;
40     this(ulong size, HipBufferUsage usage)
41     {
42         this.size = size;
43         this.usage = getD3D11Usage(usage);
44     }
45     void bind(){}
46     void unbind()
47     {
48         _hip_d3d_context.IASetVertexBuffers(0, 0, null, null, null);
49         HipRenderer.exitOnError();
50     }
51 
52 
53     bool started = false;
54     void createBuffer(const void[] data)
55     {
56         started = true;
57         this.size = data.length;
58         D3D11_BUFFER_DESC bd;
59         bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
60         bd.Usage = usage;
61         bd.CPUAccessFlags = getD3D11_CPUUsage(usage);
62         bd.MiscFlags = 0u;
63         bd.ByteWidth = cast(uint)size;
64         bd.StructureByteStride = 0;
65 
66         D3D11_SUBRESOURCE_DATA sd;
67         sd.pSysMem = cast(void*)data.ptr;
68 
69         //TODO: Check failure
70 
71         d3dCall(() => _hip_d3d_device.CreateBuffer(&bd, &sd, &buffer));
72         
73         HipRenderer.exitOnError();
74     }
75     void setData(const(void)[] data)
76     {
77         if(data == null || data.length == 0)
78             return;
79         createBuffer(data);
80     }
81     void updateData(int offset, const (void)[] data)
82     {
83         if(data.length + offset > this.size)
84         {
85             ErrorHandler.assertExit(false,
86             "Tried to set data with size "~to!string(size)~" and offset "~to!string(offset)~
87             "for vertex buffer with size "~to!string(this.size));
88         }
89 
90         D3D11_MAPPED_SUBRESOURCE resource;
91         _hip_d3d_context.Map(buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &resource);
92         memcpy(resource.pData+offset, data.ptr, data.length);
93         _hip_d3d_context.Unmap(buffer, 0);
94         HipRenderer.exitOnError();
95     }
96 }
97 class Hip_D3D11_IndexBufferObject : IHipIndexBufferImpl
98 {
99     immutable D3D11_USAGE usage;
100     ID3D11Buffer buffer;
101     uint count;
102     ulong size;
103     this(uint count, HipBufferUsage usage)
104     {
105         this.size = count*index_t.sizeof;
106         this.count = count;
107         this.usage = getD3D11Usage(usage);
108     }
109     protected void createBuffer(uint count, void* data)
110     {
111         this.size = count*index_t.sizeof;
112         D3D11_BUFFER_DESC bd;
113         bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
114         bd.Usage = usage;
115         bd.CPUAccessFlags = getD3D11_CPUUsage(usage);
116         bd.MiscFlags = 0u;
117         bd.ByteWidth = cast(uint)this.size;
118         bd.StructureByteStride = 0;
119         D3D11_SUBRESOURCE_DATA sd;
120         sd.pSysMem = cast(void*)data;
121         //TODO: Check failure
122         _hip_d3d_device.CreateBuffer(&bd, &sd, &buffer);
123     }
124     void bind()
125     {
126         static if(is(index_t == uint))
127             _hip_d3d_context.IASetIndexBuffer(buffer, DXGI_FORMAT_R32_UINT, 0);
128         else
129             _hip_d3d_context.IASetIndexBuffer(buffer, DXGI_FORMAT_R16_UINT, 0);
130     }
131     void unbind()
132     {
133         static if(is(index_t == uint))
134             _hip_d3d_context.IASetIndexBuffer(null, DXGI_FORMAT_R32_UINT, 0);
135         else
136             _hip_d3d_context.IASetIndexBuffer(null, DXGI_FORMAT_R16_UINT, 0);
137     }
138 
139     /**
140     * If the count is 0, it means that it should create the vertex buffero
141     * with its creation size
142     */
143     void setData(const index_t[] data)
144     {
145         if(count == 0)
146         {
147             createBuffer(this.count, cast(void*)data.ptr);
148             return;
149         }
150         createBuffer(cast(index_t)data.length, cast(void*)data.ptr);
151     }
152     void updateData(int offset, const index_t[] data)
153     {
154         if(data.length*index_t.sizeof + offset >= this.size)
155         {
156             ErrorHandler.assertExit(false, 
157             "Tried to set data with size "~to!string(data.length*index_t.sizeof)~" and offset "~to!string(offset)~
158             "for vertex buffer with size "~to!string(this.size));
159         }
160         D3D11_MAPPED_SUBRESOURCE resource;
161         _hip_d3d_context.Map(buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &resource);
162         memcpy(resource.pData+offset, data.ptr, data.length*index_t.sizeof);
163         _hip_d3d_context.Unmap(buffer, 0);
164         HipRenderer.exitOnError();
165     }
166 }
167 
168 class Hip_D3D11_VertexArrayObject : IHipVertexArrayImpl
169 {
170     ID3D11InputLayout inputLayout;
171     D3D11_INPUT_ELEMENT_DESC[] descs;
172     uint stride;
173     this(){}
174     void bind(IHipVertexBufferImpl vbo, IHipIndexBufferImpl ebo)
175     {
176         static uint offset = 0;
177         /** It must return silently to support opengl VAO binding*/
178         if(inputLayout is null)
179             return;
180         Hip_D3D11_VertexBufferObject v = cast(Hip_D3D11_VertexBufferObject)vbo;
181         _hip_d3d_context.IASetInputLayout(inputLayout);
182         _hip_d3d_context.IASetVertexBuffers(0u, 1u, &v.buffer, &stride, &offset);
183         ebo.bind();
184         HipRenderer.exitOnError();
185     }
186     void unbind(IHipVertexBufferImpl vbo, IHipIndexBufferImpl ebo)
187     {
188         if(vbo is null)
189             return;
190         vbo.unbind();
191         ebo.unbind();
192         _hip_d3d_context.IASetInputLayout(null);
193         HipRenderer.exitOnError();
194     }
195     void setAttributeInfo(ref HipVertexAttributeInfo info, uint stride)
196     {
197         this.stride = stride;
198         D3D11_INPUT_ELEMENT_DESC desc;
199         desc.SemanticName = info.name.toStringz;
200         desc.SemanticIndex = 0;
201         // desc.SemanticIndex = info.index;
202         desc.Format = _hip_d3d_getFormatFromInfo(info);
203         desc.InputSlot = 0;
204         desc.AlignedByteOffset = info.offset;
205         desc.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
206         desc.InstanceDataStepRate = 0;
207         descs~= desc;
208     }
209     void createInputLayout(Shader s)
210     {
211         if(ErrorHandler.assertErrorMessage(s !is null, "D3D11 VAO Error", "Error at creating input layout"))
212             return;
213         Hip_D3D11_VertexShader vs = cast(Hip_D3D11_VertexShader)s.vertexShader;
214 
215         
216         _hip_d3d_device.CreateInputLayout(descs.ptr, cast(uint)descs.length,
217         vs.shader.GetBufferPointer(), vs.shader.GetBufferSize(), &inputLayout);
218         HipRenderer.exitOnError();
219     }
220 }
221 
222 private int getD3D11Usage(HipBufferUsage usage)
223 {
224     switch(usage) with(HipBufferUsage)
225     {
226         default:
227         case DEFAULT:
228             return D3D11_USAGE_DEFAULT;
229         case DYNAMIC:
230             return D3D11_USAGE_DYNAMIC;
231         case STATIC:
232             return D3D11_USAGE_IMMUTABLE;
233     }
234 }
235 
236 private int getD3D11_CPUUsage(D3D11_USAGE usage)
237 {
238     switch(usage)
239     {
240         default:
241         case D3D11_USAGE_DEFAULT:
242             return D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
243         case D3D11_USAGE_DYNAMIC:
244             return D3D11_CPU_ACCESS_WRITE;
245         case D3D11_USAGE_IMMUTABLE:
246             return 0;
247     }
248 }
249 
250 private DXGI_FORMAT _hip_d3d_getFormatFromInfo(ref HipVertexAttributeInfo info)
251 {
252     DXGI_FORMAT ret;
253     switch(info.valueType)
254     {
255         case HipAttributeType.Rgba32:
256             return DXGI_FORMAT_R8G8B8A8_UNORM;
257         case HipAttributeType.Float:
258             switch(info.count)
259             {
260                 case 1: ret = DXGI_FORMAT_R32_FLOAT; break;
261                 case 2: ret = DXGI_FORMAT_R32G32_FLOAT; break;
262                 case 3: ret = DXGI_FORMAT_R32G32B32_FLOAT; break;
263                 case 4: ret = DXGI_FORMAT_R32G32B32A32_FLOAT; break;
264                 default:
265                     ErrorHandler.showErrorMessage("DXGI Format Error",
266                     "Unknown format type from float with length " ~ to!string(info.count));
267             }
268             break;
269         case HipAttributeType.Uint:
270             switch(info.count)
271             {
272                 case 1: ret = DXGI_FORMAT_R32_UINT; break;
273                 default:
274                     ErrorHandler.showErrorMessage("DXGI Format Error",
275                     "Unknown format type from uint with length " ~ to!string(info.count));
276             }
277             break;
278         case HipAttributeType.Bool:
279         case HipAttributeType.Int:
280             switch(info.count)
281             {
282                 case 1: ret = DXGI_FORMAT_R32_SINT; break;
283                 case 2: ret = DXGI_FORMAT_R32G32_SINT; break;
284                 case 3: ret = DXGI_FORMAT_R32G32B32_SINT; break;
285                 case 4: ret = DXGI_FORMAT_R32G32B32A32_SINT; break;
286                 default:
287                     ErrorHandler.showErrorMessage("DXGI Format Error",
288                     "Unknown format type from int/bool with length " ~ to!string(info.count));
289             }
290             break;
291         default:
292             ErrorHandler.showErrorMessage("DXGI Format Error", "Unknown format type from info");
293             break;
294     }
295     return ret;
296 }